<template>
  <BasicModal
    v-bind="$attrs"
    @register="register"
    showFooter
    :title="title"
    width="600px"
    @ok="handleSubmit"
  >
    <UploadDragger
      name="file"
      :fileList="fileList"
      :accept="getStringAccept"
      :beforeUpload="handleBefore"
      :maxCount="maxCount"
      :multiple="multiple"
      @remove="handleDel"
    >
      <div class="drag-icon">
        <img :src="uploadIcon" class="upload-icon" />
        <!-- <CloudUploadOutlined class="upload-icon" /> -->
        <p class="temp upload-tip">点击或将文件拖拽到这里上传</p>
        <div class="temp pt-1">
          <span v-if="getStringAccept">仅允许导入{{ getStringAccept }}格式文件。</span>
          <a @click.stop="handleTemp" v-if="tempApi"> 点击下载模板 </a>
        </div>
      </div>
    </UploadDragger>
  </BasicModal>
  <span @click.stop="handleModal">
    <slot></slot>
  </span>
</template>

<script lang="tsx">
  import { defineComponent, computed, ref, unref } from 'vue';
  import { isFunction } from '/@/utils/is';
  import type { UploadProps, UploadFile } from 'ant-design-vue';
  import { Upload } from 'ant-design-vue';
  import { useMessage } from '/@/hooks/web/useMessage';

  import { Result } from '/#/axios';
  import { warn } from '/@/utils/log';
  // import { CloudUploadOutlined } from '@ant-design/icons-vue';
  import { propTypes } from '/@/utils/propTypes';
  import { downloadByData } from '/@/utils/file/download';
  import { BasicModal, useModal } from '/@/components/Modal';
  import { BasicTable } from '/@/components/Table';
  import { UploadResultStatus } from './typing';
  import { columns } from './data';
  import uploadIcon from '/@/assets/images/upload-icon.png';

  const UploadDragger = Upload.Dragger;

  export default defineComponent({
    name: 'BasicImport',
    components: { BasicModal, UploadDragger },
    props: {
      accept: { type: Array as PropType<string[]>, default: () => [] },
      maxCount: propTypes.number,
      multiple: propTypes.bool.def(false),
      fileName: propTypes.string.def('temp.xlsx'),
      title: propTypes.string.def('导入'),
      tempApi: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
      api: { type: Function as PropType<PromiseFn> },
    },
    emits: ['error', 'success'],
    setup(props, { emit }) {
      const { createErrorModal } = useMessage();

      const getStringAccept = computed(() => {
        return unref(props.accept)
          .map((item) => {
            if (item.indexOf('/') > 0 || item.startsWith('.')) {
              return item;
            } else {
              return `.${item}`;
            }
          })
          .join(',');
      });
      const [register, { setModalProps, openModal, closeModal }] = useModal();

      function handleModal() {
        openModal();
      }
      const fileList = ref<UploadProps['fileList']>([]);

      const handleBefore: UploadProps['beforeUpload'] = (_, FileList) => {
        fileList.value = FileList;

        return false;
      };

      async function handleSubmit() {
        setModalProps({ confirmLoading: true });
        const list = unref(fileList)!;
        // await api();
        try {
          const data = await Promise.all(
            list.map((item) => {
              return uploadApiByItem(item);
            }),
          );

          const errorList = data.filter((item: any) => !item.success);
          if (errorList.length > 0) throw errorList;

          const ret = list.map((el) => ({ name: el.name, res: el.response as Result }));
          const errList = ret.filter((el) => el.res.code !== 0);

          if (errList.length) {
            const errDatas = errList
              .map((el) => {
                el.res.data ??
                  [].forEach((f) => {
                    f.name = el.name;
                  });
                return el.res.data;
              })
              .flat();
            createErrorModal({
              title: '错误提示',
              width: '50%',
              content: () => (
                <BasicTable showIndexColumn={false} columns={columns} dataSource={errDatas} />
              ),
            });
            emit('error', errList);

            return;
          }

          emit('success', ret);
          closeModal();
        } catch (e) {
          throw e;
        } finally {
          fileList.value = [];
          setModalProps({ confirmLoading: false });
        }
      }
      async function uploadApiByItem(item: UploadFile) {
        const { api } = props;
        if (!api || !isFunction(api)) {
          return warn('upload api must exist and be a function');
        }

        try {
          item.status = UploadResultStatus.UPLOADING;
          const { data } = await props.api?.(
            {
              file: item,
              name: 'file',
              filename: props.fileName,
            },
            function onUploadProgress(progressEvent: ProgressEvent) {
              const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
              item.percent = complete;
            },
          );

          item.status = UploadResultStatus.SUCCESS;
          item.response = data;
          return {
            success: true,
            data,
            error: null,
          };
        } catch (e) {
          item.status = UploadResultStatus.ERROR;
          return {
            success: false,
            error: e,
          };
        }
      }
      async function handleTemp() {
        const { tempApi, fileName } = props;
        if (!isFunction(tempApi)) return;
        const file = await tempApi();
        downloadByData(file as BlobPart, fileName);
      }

      async function handleDel(file) {
        if (fileList.value) {
          const idx = fileList.value.findIndex((f) => f.uid === file.uid);
          if (idx > -1) {
            fileList.value?.splice(idx, 1);
            return true;
          }
        }
      }

      return {
        handleDel,
        uploadIcon,
        register,
        fileList,
        handleModal,
        handleSubmit,
        handleTemp,
        handleBefore,
        getStringAccept,
      };
    },
  });
</script>
<style lang="less" scoped>
  .drag-icon {
    position: relative;
    top: 30px;
  }

  .upload-icon {
    margin: 0 auto 12px auto;
    // font-size: 8em;
    // width: 112px;
    // color: @primary-color;
  }

  :deep(.ant-upload.ant-upload-drag) {
    border: none;
    background-color: #fff;
  }

  .temp {
    font-size: 0.9em;
  }

  .upload-tip {
    font-size: 14px;
    font-family: PingFang SC-Regular, PingFang SC;
    font-weight: 400;
    color: #999999;
  }

  em {
    font-style: normal;
    color: @primary-color;
  }
</style>
